import { MongodbClient } from "../lib/db.client.mongodb";
import { PgClient } from "../lib/db.client.pg";

import { Formula, TonTpl, TonTplGroup, User } from "qqlx-core";
import { getConditionMatchStr, TonTplSchema, TonTplGroupSchema, FormulaSchema, getTplIvId } from "qqlx-cdk";

import { User as OldUser, UserWeChat as OldUserWeChat } from "../../../qqlx.old/qqlx-core";
import { Corp as OldCorp } from "../../../qqlx.old/qqlx-core";
import { Cabinet, CabinetUnit, ENUM_POUNDS_FORMULA, MAP_ENUM_POUNDS_FORMULA } from "../../../qqlx.old/qqlx-core";

import { FormulaDao } from "../dao/pond";
import { TonTplGroupDao, TonTplDao } from "../dao/river";
import { ObjectId } from "mongodb";

export async function doTonTplInsert(corpId: string, user_old_new_map: Map<OldUser["_id"], User>) {
  const mongodbClient = new MongodbClient("mongodb://localhost:27017/qqlx");
  const pgClient = new PgClient("127.0.0.1", "5432", "production", "postgres", "postgres");

  console.group("\n开始迁移mongo商品模板数据");
  const stat = { before: 0, wanner: 0, now: 0 };

  // 新用户公式
  const userFormulaMap = new Map<User["uuid32"], Formula>();

  try {
    await mongodbClient.start();
    const colCorps = mongodbClient.getCollection("corps");
    const corpExist = (await colCorps.findOne<OldCorp>({ _id: corpId as unknown as ObjectId })) as OldCorp;
    const corpQuery = { corpId: corpExist._id as unknown as ObjectId };

    const colCabinet = mongodbClient.getCollection("cabinets");
    const oldCabinets = await colCabinet.find<Cabinet>(corpQuery).toArray();
    const oldCabinetIds = oldCabinets.map((c) => c._id);
    console.log("旧数据（商品分组）", oldCabinets.length);

    const colCabinetUnit = mongodbClient.getCollection("cabinetunits");
    const oldCabinetUnits = await colCabinetUnit.find<CabinetUnit>({ cabinetId: { $in: oldCabinetIds } }).toArray();
    console.log("旧数据（商品模板）", oldCabinetUnits.length);
    stat.wanner = oldCabinets.length + oldCabinetUnits.length;

    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░▄█▀▀▀▀▀█▄░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▄█░░▄▄▄░░█▄░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▄▄█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▀▄▀▄▄▄▄▄▀▄▀░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

    const pgClientIns = await pgClient.start();
    const formulaDao = new FormulaDao(pgClientIns.getRepository<Formula>(FormulaSchema));
    const tplGroupDao = new TonTplGroupDao(pgClientIns.getRepository<TonTplGroup>(TonTplGroupSchema));
    const tplDao = new TonTplDao(pgClientIns.getRepository<TonTpl>(TonTplSchema));

    const master = user_old_new_map.get(corpExist.userId) as User;
    const condis = [getConditionMatchStr("refOwnerUUid32", master.uuid32)];

    // 迁移公式
    const formulaExist = await formulaDao.queryMatch(condis);
    if (formulaExist.firstMatch) {
      userFormulaMap.set(master.uuid32, formulaExist.firstMatch);
    } else {
      const formulaName = MAP_ENUM_POUNDS_FORMULA.get(ENUM_POUNDS_FORMULA.TS_PLATE)?.text || "未知公式";
      const formulaSchema = getDefaultFormula(master.uuid32, formulaName);
      formulaSchema.desc = "7.85*(A/10)*(B/10)*(C/10)/1000/1000";
      const formulaEntity = await formulaDao.insertOne(formulaSchema);
      userFormulaMap.set(master.uuid32, formulaEntity);
    }

    // 迁移商品模板
    const tplGroupCount = await tplGroupDao.count(condis);
    const tplCount = await tplDao.count(condis);
    stat.before = tplGroupCount + tplCount;

    if (tplGroupCount + tplCount === 0) {
      for (const cabi of oldCabinets) {
        const groupSchema = getDefaultGroup(master.uuid32, cabi.name);

        if (cabi.formula === ENUM_POUNDS_FORMULA.TS_PLATE) {
          groupSchema.formulaName = MAP_ENUM_POUNDS_FORMULA.get(ENUM_POUNDS_FORMULA.TS_PLATE)?.text || "未知公式";
          groupSchema.formulaContent = "7.85*(A/10)*(B/10)*(C/10)/1000/1000";
        }
        const groupEntity = await tplGroupDao.insertOne(groupSchema); // 新创建一个数据包

        // 为数据包补充商品模板
        const tplSchemaLs = oldCabinetUnits
          .filter((unit) => unit.cabinetId === cabi._id)
          .map((unit) => getDefaultTonTpl(master.uuid32, groupEntity.id, cabi, unit));
        await tplDao.insertMany(tplSchemaLs);
      }
    }

    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░▄█▀▀▀▀▀█▄░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▄█░░▄▄▄░░█▄░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▀▀█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░█░░█▄▄█░░█░░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░▀▄▀▄▄▄▄▄▀▄▀░░░░░░░░░░░░░░░░░░░░░░░░░░
    // ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

    const tplGroupCount2 = await tplGroupDao.count(condis);
    const tplCount2 = await tplDao.count(condis);
    stat.now = tplGroupCount2 + tplCount2;

    console.log(`🔴迁移前 >> 迁移后 / tpl/group`, stat.before, stat.now);
    console.log(`期望`, stat.wanner);
    console.log(`📉误差`, stat.now - stat.before - stat.wanner);
    console.groupEnd();
    console.log("====================================");
  } finally {
    await pgClient.stop();
    await mongodbClient.stop();
  }

  return { userFormulaMap };
}

function getDefaultGroup(userId: string, name: string) {
  const schema: TonTplGroup = new TonTplGroupSchema();
  schema.refOwnerUUid32 = userId;
  schema.name = name;
  return schema;
}

function getDefaultFormula(userId: string, name: string) {
  const schema: Formula = new FormulaSchema();
  schema.refOwnerUUid32 = userId;
  schema.name = name;
  return schema;
}

function getDefaultTonTpl(userId: string, groupId: TonTplGroup["id"], entityGroup: Cabinet, entity: CabinetUnit) {
  const schema: TonTpl = new TonTplSchema();
  schema.timeCreate = entity.timeCreate.toString();
  schema.timeUpdate = entity.timeUpdate.toString();
  schema.refOwnerUUid32 = userId;
  schema.refTonTplGroupId = groupId;

  schema.name = entity.name;
  schema.norm = entity.norm || "-";
  schema.unit = entityGroup.unit;
  schema.ivid = getTplIvId(schema, "");
  return schema;
}
